# coding: utf-8
"""
@python version : python3.10
@file name      : serializers.py
@date           : 2024/4/28 13:49
@author         : ziyang.yang@aliyun.com
@gitee          : https://gitee.com/ziyangyang1318
@blog           : www.yangziyang.top
@describe       : 
"""
import uuid
from typing import Dict, Any

from .models import Book, UserInfo, TokenInfo
from rest_framework import serializers
from collections import OrderedDict
from rest_framework.fields import SkipField
from rest_framework.relations import PKOnlyObject
from rest_framework.exceptions import ValidationError


class HookSerializer:
    def to_representation(self, instance):
        """
        Object instance -> Dict of primitive datatypes.
        """
        ret = OrderedDict()
        fields = self._readable_fields

        for field in fields:

            # 重写字段检测方法
            # 判断序列化类中是否有 yzy_字段名的方法，如果有则调用这个方法，如果没有就往下面走，保持原有功能
            if hasattr(self, 'yzy_%s' % field.field_name):
                value = getattr(self, 'yzy_%s' % field.field_name)(instance)
                ret[field.field_name] = value
            else:
                try:
                    attribute = field.get_attribute(instance)
                except SkipField:
                    continue
                check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
                if check_for_none is None:
                    ret[field.field_name] = None
                else:
                    ret[field.field_name] = field.to_representation(attribute)

        return ret


# Create your views here.

class BookSerializer(HookSerializer, serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ('id', 'title', 'price', 'publish', 'book_type')

    # title = serializers.CharField(max_length=8)
    # price = serializers.IntegerField()
    # publish = serializers.IntegerField()
    # # publish_id = serializers.CharField(write_only=True)
    # # book_publish = serializers.SerializerMethodField(read_only=True)
    # # book_type = serializers.IntegerField(write_only=True)
    # # type_name = serializers.SerializerMethodField()
    # book_type = serializers.IntegerField()

    # 定义返回数据的自定义钩子
    def yzy_publish(self, obj):
        return obj.publish.name

    def yzy_book_type(self, obj):
        return obj.get_book_type_display()

    # 重写filed方法
    def to_representation(self, instance):
        """
        Object instance -> Dict of primitive datatypes.
        """
        ret = OrderedDict()
        fields = self._readable_fields

        for field in fields:

            # 重写字段检测方法
            # 判断序列化类中是否有 yzy_字段名的方法，如果有则调用这个方法，如果没有就往下面走，保持原有功能
            if hasattr(self, 'yzy_%s' % field.field_name):
                value = getattr(self, 'yzy_%s' % field.field_name)(instance)
                ret[field.field_name] = value
            else:
                try:
                    attribute = field.get_attribute(instance)
                except SkipField:
                    continue
                check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
                if check_for_none is None:
                    ret[field.field_name] = None
                else:
                    ret[field.field_name] = field.to_representation(attribute)

        return ret

    def get_type_name(self, obj):
        return obj.get_book_type_display()

    def get_book_publish(self, obj):
        return {'name': obj.publish.name, 'city': obj.publish.city}

    # 序列化器局部钩子对字段进行校验
    def validate_price(self, price):
        if price < 0:
            raise serializers.ValidationError("价格不能小于0")
        else:
            return price

    def validate_title(self, title):
        obj = Book.objects.filter(title=title).first()
        if obj:
            raise serializers.ValidationError(f"{title}已存在")
        else:
            return title

    # 全局钩子，传入所有的字段
    # def validate(self,attrs):
    #     pass
    def create(self, validated_data):
        return Book.objects.create(**validated_data)


class BookssSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'


class UserInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserInfo
        fields = "__all__"

    def validate(self, attrs):
        # 对用户名密码进行校验
        username = attrs.get("username")
        password = attrs.get("password")
        user = UserInfo.objects.filter(username=username, password=password).first()
        if user:
            # 验证通过后,需要对给这个用户返回一个token,并写入数据库
            # 如果有token则更新，如果没有则创建
            token = uuid.uuid4()
            TokenInfo.objects.update_or_create(user=user, defaults={"token": token})
            attrs['token'] = token
            return attrs
        else:
            raise ValidationError(detail='用户名或密码错误')


# 自定义jwt验证
class UserLoginSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserInfo
        fields = ["username", "password"]

    def validate(self, attrs):
        # 对用户名密码进行校验
        username = attrs.get("username")
        password = attrs.get("password")
        user = UserInfo.objects.filter(username=username, password=password).first()
        if user:
            # 验证通过后,进行token生成
            refresh = TokenObtainPairSerializer().get_token(user)
            # 自定义token payload数据
            refresh['username'] = user.username
            # 自定义登录成功后的返回格式
            data = {
                'code': 100,
                'msg': '登陆成功',
                'username': user.username,
                'token': str(refresh.access_token)
            }
            return data
        else:
            raise ValidationError(detail='用户名或密码错误')


# 自定义 jwt 登成功之后返回格式

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer


class MyTokenObtainPairSerializer(TokenObtainPairSerializer):

    def validate(self, attrs: Dict[str, Any]) -> Dict[str, str]:
        old_data = super().validate(attrs)
        data = {
            "code": 200,
            "msg": "login successfully",
            "token": old_data.get("access"),
            "username": self.user.username,
            "email": self.user.email,
        }
        return data

    # 自定义token中payload 信息
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['username'] = user.username
        token['email'] = user.email
        return token
